package middleware

import (
	"encoding/json"
	"fmt"
	"getaway/basic/config"
	behaviorproto "getaway/basic/proto/behaviorproto"
	"github.com/gin-gonic/gin"
	"strings"
	"sync"
	"time"
)

// 定义页面路径常量
type PageType string

type DeviceType string

const (
	// 页面类型定义
	PageHome          PageType = "首页"
	PageServiceSelect PageType = "服务选择页"
	PagePayment       PageType = "支付页"
	PageOrderDetail   PageType = "订单详情页"
	PageDestination   PageType = "目的地输入页"
	PageUserProfile   PageType = "个人中心页"
	PageVehicleDetail PageType = "车辆详情页"
	PageOrderConfirm  PageType = "订单确认页"
	PageOrderList     PageType = "订单列表页"

	// 点击行为类型
	ClickViewCarDetail = "查看车辆详情"
	ClickPayOrder      = "支付订单"
	ClickCancelOrder   = "取消订单"
	ClickSubmitOrder   = "提交订单"
	ClickChooseDriver  = "选择司机"
	ClickRateDriver    = "评价司机"
	ClickShareOrder    = "分享订单"
	ClickCallDriver    = "联系司机"
	ClickAddFavorites  = "添加收藏"
	ClickUseCoupon     = "使用优惠券"

	// 设备类型
	DeviceTypeMobile  DeviceType = "移动设备"
	DeviceTypeDesktop DeviceType = "桌面设备"
	DeviceTypeTablet  DeviceType = "平板设备"
	DeviceTypeUnknown DeviceType = "未知设备"

	// 会话Cookie名称
	SessionCookieName = "behavior_session_id"
	// 首次访问标记Cookie名称
	FirstVisitCookieName = "first_visit"
	// 上次访问页面Cookie名称
	LastVisitCookieName = "last_visit"
)

// 页面访问数据
type PageVisitData struct {
	StartTime time.Time
	PagePath  string
	PageName  PageType
	SessionID string
	UserID    interface{}
}

// 会话访问数据存储
var (
	sessionVisitData sync.Map
)

// EnhancedBehaviorTracker 行为追踪中间件
func EnhancedBehaviorTracker() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取会话ID
		sessionID := getOrCreateSessionID(c)
		// 获取用户ID
		userId, _ := c.Get("userId")
		// 获取用户IP
		userIP := c.ClientIP()
		// 获取当前页面路径
		currentPath := c.Request.URL.Path
		// 获取当前页面名称
		pageName := getPageName(currentPath)
		// 获取设备类型
		deviceType := getDeviceType(c.Request.UserAgent())
		// 获取请求参数
		params := getRequestParams(c)

		// 检查是否为首次访问
		isFirstVisit := checkAndMarkFirstVisit(c)
		// 记录访问开始时间
		startTime := time.Now()

		// 存储当前页面访问数据，用于后续计算停留时间
		visitData := &PageVisitData{
			StartTime: startTime,
			PagePath:  currentPath,
			PageName:  pageName,
			SessionID: sessionID,
			UserID:    userId,
		}
		sessionVisitData.Store(sessionID, visitData)

		// 记录访问记录（包括首次访问标记）
		recordVisit(c, userId, userIP, sessionID, currentPath, string(pageName), string(deviceType), isFirstVisit, params)

		// 处理请求
		c.Next()

		// 请求处理完成后，记录停留时间
		duration := time.Since(startTime)
		recordStayTime(c, userId, sessionID, currentPath, string(pageName), duration)

		// 更新最后访问页面信息
		updateLastVisitInfo(c, currentPath, pageName)

		// 从会话数据中删除本次访问数据
		sessionVisitData.Delete(sessionID)
	}
}

// 从请求中获取或生成会话ID
func getOrCreateSessionID(c *gin.Context) string {
	// 尝试从cookie中获取sessionID
	cookie, err := c.Cookie(SessionCookieName)
	if err == nil && cookie != "" {
		return cookie
	}

	// 如果没有，则生成新的sessionID
	sessionID := fmt.Sprintf("%d_%s_%s", time.Now().UnixNano(), c.ClientIP(), strings.Replace(c.Request.UserAgent()[:20], " ", "_", -1))

	// 设置cookie，有效期为30天
	c.SetCookie(SessionCookieName, sessionID, 86400*30, "/", "localhost", false, true)
	return sessionID
}

// 根据请求路径获取页面名称
func getPageName(path string) PageType {
	path = strings.ToLower(path)
	if strings.Contains(path, "home") || path == "/" {
		return PageHome
	} else if strings.Contains(path, "service") && strings.Contains(path, "select") {
		return PageServiceSelect
	} else if strings.Contains(path, "payment") || strings.Contains(path, "pay") {
		return PagePayment
	} else if strings.Contains(path, "order") && strings.Contains(path, "detail") {
		return PageOrderDetail
	} else if strings.Contains(path, "destination") {
		return PageDestination
	} else if strings.Contains(path, "profile") || (strings.Contains(path, "user") && !strings.Contains(path, "login") && !strings.Contains(path, "register")) {
		return PageUserProfile
	} else if strings.Contains(path, "vehicle") && strings.Contains(path, "detail") {
		return PageVehicleDetail
	} else if strings.Contains(path, "order") && strings.Contains(path, "confirm") {
		return PageOrderConfirm
	} else if strings.Contains(path, "order") && strings.Contains(path, "list") {
		return PageOrderList
	}
	// 如果没有匹配的预定义页面，则直接返回路径的最后一部分作为页面名称
	parts := strings.Split(path, "/")
	lastPart := "unknown"
	if len(parts) > 0 {
		for i := len(parts) - 1; i >= 0; i-- {
			if parts[i] != "" {
				lastPart = parts[i]
				break
			}
		}
	}
	return PageType(lastPart)
}

// 获取设备类型
func getDeviceType(userAgent string) DeviceType {
	userAgent = strings.ToLower(userAgent)
	if strings.Contains(userAgent, "mobile") || strings.Contains(userAgent, "android") || strings.Contains(userAgent, "iphone") || strings.Contains(userAgent, "ipad") {
		if strings.Contains(userAgent, "ipad") || strings.Contains(userAgent, "tablet") {
			return DeviceTypeTablet
		}
		return DeviceTypeMobile
	}
	return DeviceTypeDesktop
}

// 获取请求参数
func getRequestParams(c *gin.Context) map[string]string {
	params := make(map[string]string)

	// 获取Query参数
	for key, values := range c.Request.URL.Query() {
		if len(values) > 0 {
			params[key] = values[0]
		}
	}

	// 如果是POST请求，尝试获取Form参数
	if c.Request.Method == "POST" {
		c.Request.ParseForm()
		for key, values := range c.Request.Form {
			if len(values) > 0 {
				params[key] = values[0]
			}
		}
	}

	// 限制参数数量，避免过大
	if len(params) > 50 {
		limitedParams := make(map[string]string)
		count := 0
		for k, v := range params {
			limitedParams[k] = v
			count++
			if count >= 50 {
				break
			}
		}
		return limitedParams
	}

	return params
}

// 检查并标记首次访问
func checkAndMarkFirstVisit(c *gin.Context) bool {
	// 尝试从cookie中获取首次访问标记
	cookie, err := c.Cookie(FirstVisitCookieName)
	if err == nil && cookie == "1" {
		return false
	}

	// 标记为首次访问
	c.SetCookie(FirstVisitCookieName, "1", 86400*365, "/", "localhost", false, true)
	return true
}

// 更新最后访问页面信息
func updateLastVisitInfo(c *gin.Context, path string, pageName PageType) {
	// 构建最后访问信息
	lastVisitInfo := fmt.Sprintf("%d|%s|%s", time.Now().UnixNano()/int64(time.Millisecond), path, pageName)
	// 设置cookie
	c.SetCookie(LastVisitCookieName, lastVisitInfo, 86400, "/", "localhost", false, true)
}

// 记录访问记录
func recordVisit(c *gin.Context, userId interface{}, userIP, sessionID, path, pageName, deviceType string, isFirstVisit bool, params map[string]string) {
	// 异步记录，不阻塞主流程
	go func() {
		// 构建请求
		req := &behaviorproto.RecordVisitReq{
			RequestId:    sessionID,
			UserId:       getUserIdInt64(userId),
			Path:         path,
			Method:       c.Request.Method,
			Ip:           userIP,
			UserAgent:    c.Request.UserAgent(),
			Referer:      c.Request.Referer(),
			DeviceId:     deviceType,
			VisitTime:    time.Now().UnixNano() / int64(time.Millisecond),
			IsFirstVisit: isFirstVisit,
			Params:       params,
		}

		// 调用行为服务记录访问
		if config.BehaviorClient != nil {
			_, err := config.BehaviorClient.RecordVisit(c, req)
			if err != nil {
				fmt.Printf("记录访问失败: %v\n", err)
			}
		} else {
			// 如果没有连接到behavior服务，打印日志
			fmt.Printf("记录访问: 用户ID=%v, IP=%s, 会话ID=%s, 页面=%s, 首次访问=%v\n", userId, userIP, sessionID, pageName, isFirstVisit)
		}
	}()
}

// 记录点击行为（公共函数，供其他地方调用）
func RecordClickBehavior(c *gin.Context, userId interface{}, behaviorType string, details map[string]interface{}) {
	sessionID := getOrCreateSessionID(c)
	path := c.Request.URL.Path
	pageName := getPageName(path)
	userIP := c.ClientIP()
	deviceType := getDeviceType(c.Request.UserAgent())

	// 异步记录，不阻塞主流程
	go func() {
		// 序列化details
		detailsJSON, _ := json.Marshal(details)

		// 构建请求
		req := &behaviorproto.RecordClickReq{
			RequestId:   sessionID,
			UserId:      getUserIdInt64(userId),
			ElementId:   string(pageName),
			ElementType: behaviorType,
			Action:      "click",
			PageUrl:     path,
			Ip:          userIP,
			DeviceId:    string(deviceType),
			ClickTime:   time.Now().UnixNano() / int64(time.Millisecond),
			Params:      map[string]string{"details": string(detailsJSON)},
		}

		// 调用行为服务记录点击
		if config.BehaviorClient != nil {
			_, err := config.BehaviorClient.RecordClick(c, req)
			if err != nil {
				fmt.Printf("记录点击行为失败: %v\n", err)
			}
		} else {
			// 如果没有连接到behavior服务，打印日志
			fmt.Printf("记录点击行为: 用户ID=%v, 类型=%s, 页面=%s\n", userId, behaviorType, pageName)
		}
	}()
}

// 记录停留时间
func recordStayTime(c *gin.Context, userId interface{}, sessionID, path, pageName string, duration time.Duration) {
	// 异步记录，不阻塞主流程
	go func() {
		// 构建请求
		req := &behaviorproto.RecordStayTimeReq{
			RequestId:    sessionID,
			UserId:       getUserIdInt64(userId),
			PageUrl:      path,
			StayDuration: duration.Milliseconds(),
			StartTime:    time.Now().Add(-duration).UnixNano() / int64(time.Millisecond),
			EndTime:      time.Now().UnixNano() / int64(time.Millisecond),
			Ip:           c.ClientIP(),
			DeviceId:     string(getDeviceType(c.Request.UserAgent())),
		}

		// 调用行为服务记录停留时间
		if config.BehaviorClient != nil {
			_, err := config.BehaviorClient.RecordStayTime(c, req)
			if err != nil {
				fmt.Printf("记录停留时间失败: %v\n", err)
			}
		} else {
			// 如果没有连接到behavior服务，打印日志
			fmt.Printf("记录停留时间: 用户ID=%v, 页面=%s, 时长=%dms\n", userId, pageName, duration.Milliseconds())
		}
	}()
}

// 将userId转换为int64类型
func getUserIdInt64(userId interface{}) int64 {
	if userId == nil {
		return 0
	}

	// 根据不同类型进行转换
	switch v := userId.(type) {
	case int:
		return int64(v)
	case int32:
		return int64(v)
	case int64:
		return v
	case uint:
		return int64(v)
	case uint32:
		return int64(v)
	case uint64:
		return int64(v)
	case string:
		// 尝试将字符串转换为int64
		var id int64
		fmt.Sscanf(v, "%d", &id)
		return id
	default:
		return 0
	}
}

// GetSessionVisitData 获取会话访问数据（用于调试）
func GetSessionVisitData(sessionID string) (*PageVisitData, bool) {
	value, ok := sessionVisitData.Load(sessionID)
	if !ok {
		return nil, false
	}

	visitData, ok := value.(*PageVisitData)
	return visitData, ok
}
